
package com.hlkj.pay.app.payment.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.exception.ExcelCommonException;
import com.hlkj.framework.caches.service.RedisTemplateService;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.provider.Aes256EncryptionProvider;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.common.IAuthCodeService;
import com.hlkj.pay.app.common.IUploadService;
import com.hlkj.pay.app.merchant.IMerchantConfigAppService;
import com.hlkj.pay.app.merchant.ext.dto.payment.ChannelPaymentCallBackDto;
import com.hlkj.pay.app.order.impl.OrderHandler;
import com.hlkj.pay.app.payment.IMerchantPaymentAppService;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.common.OpenApiResultCode;
import com.hlkj.pay.dto.LocalMerchantRequest;
import com.hlkj.pay.dto.merchant.MerchantAcctBalanceDto;
import com.hlkj.pay.dto.merchant.config.MerchantPaymentConfigDto;
import com.hlkj.pay.dto.merchant.config.MerchantPaymentConfigMappingDto;
import com.hlkj.pay.dto.payment.*;
import com.hlkj.pay.enums.*;
import com.hlkj.pay.gateway.order.IChannelPaymentGateway;
import com.hlkj.pay.infrastructure.model.admin.AdminUserDO;
import com.hlkj.pay.infrastructure.model.common.ImportRecordDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantInfoDO;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDO;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDetailDO;
import com.hlkj.pay.service.admin.IAdminUserService;
import com.hlkj.pay.service.common.IImportRecordService;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.service.merchant.IMerchantService;
import com.hlkj.pay.service.payment.IMerchantPaymentService;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.util.OpenApiParamsUtils;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.merchant.req.payment.MerchantPaymentApproveReq;
import com.hlkj.pay.vo.merchant.req.payment.MerchantPaymentDetailReq;
import com.hlkj.pay.vo.merchant.req.payment.MerchantPaymentDetailUpdateReq;
import com.hlkj.pay.vo.merchant.req.payment.MerchantPaymentFileReq;
import com.hlkj.pay.vo.merchant.resp.payment.MerchantPaymentDetailPageResp;
import com.hlkj.pay.vo.openapi.order.req.PayOrderQueryReq;
import com.hlkj.pay.vo.openapi.order.req.PaymentCommonParamReq;
import com.hlkj.pay.vo.openapi.order.resp.PaymentApiResp;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author HlpayTeam
 * @date 2024/11/20 14:43
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Validated
public class MerchantPaymentAppServiceImpl implements IMerchantPaymentAppService {

    private final IMerchantPaymentService merchantPaymentService;

    private final IImportRecordService importRecordService;

    private final Aes256EncryptionProvider aes256EncryptionProvider;

    private final IChannelPaymentGateway channelPaymentGateway;

    private final IAuthCodeService authCodeService;

    private final IAdminUserService adminUserService;

    private final IMerchantApplicationService merchantApplicationService;

    private final IMerchantConfigAppService merchantConfigAppService;

    private final IUploadService uploadService;

    private final IMerchantService merchantService;

    private final OrderHandler orderHandler;

    private final RedisTemplateService redisTemplateService;

    @Value("${hlkj.pay.check:true}")
    private boolean check;

    @Value("${hlkj.domain}")
    private String domain;

    @Value("${hlkj.upload.hidden}")
    public String uploadHidden;

    @Value("${hlkj.upload.directory}")
    public String uploadDirectory;

    private final OrderCodeUtil orderCodeUtil;

    @Override
    public CommonResult<Void> approve(MerchantPaymentApproveReq merchantPaymentApproveReq) {
        log.info("approve merchantPaymentApproveReq:{}", JsonUtils.toJsonString(merchantPaymentApproveReq));
        try {
            MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(merchantPaymentApproveReq.getPaymentIds().get(0));
            if (merchantPaymentDto == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_NOT_EXIST);
            }
            // 管理员手机 校验
            if (MerchantEnum.PROCESS_STATUS.APPROVE.getCode().equals(merchantPaymentApproveReq.getStatus())) {
                if (check) {
                    AdminUserDO adminUserDO = adminUserService.queryUserBySn(merchantPaymentDto.getSn());
                    CommonResult<Void> voidCommonResult = authCodeService.checkAuthCode(aes256EncryptionProvider.decryptString(adminUserDO.getPhoneEncrypt()),
                            AdminUserEnum.AdminAuthCodeEnum.MERCHANT_PAYMENT, merchantPaymentApproveReq.getSmsCode());
                    if (!voidCommonResult.isSuccess()) {
                        return CommonResult.error(voidCommonResult.getCode(), voidCommonResult.getMsg());
                    }
                }
            }
            if (MerchantEnum.PROCESS_STATUS.APPROVE.getCode().equals(merchantPaymentApproveReq.getStatus())) {
                boolean extensionExist = channelPaymentGateway.extensionExist(merchantPaymentDto.getMchChannelCode());
                if (!extensionExist) {
                    return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
                }
            }
            List<MerchantPaymentDto> merchantPaymentDtos = new ArrayList<>();
            for (String paymentId : merchantPaymentApproveReq.getPaymentIds()) {
                MerchantPaymentDto merchantPayment = merchantPaymentService.queryDetailDto(paymentId);
                if (!MerchantEnum.PROCESS_STATUS.INIT.getCode().equals(merchantPayment.getStatus())) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_APPROVED);
                }
                // 更新为审核通过
                merchantPayment.setStatus(merchantPaymentApproveReq.getStatus());
                merchantPayment.getMerchantPaymentDetailList().forEach(merchantPaymentDetailDO -> {
                    merchantPaymentDetailDO.setStatus(merchantPaymentApproveReq.getStatus());
                    merchantPaymentDetailDO.setRemark(merchantPaymentApproveReq.getRemark());
                });
                merchantPaymentService.updatePayment(merchantPayment);
                merchantPaymentDtos.add(merchantPayment);
            }
            if (MerchantEnum.PROCESS_STATUS.APPROVE.getCode().equals(merchantPaymentApproveReq.getStatus())) {
                // 异步执行
                syncSubmitChannelPayment(merchantPaymentDtos);
            }
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("approve error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Async("taskExecutor")
    void syncSubmitChannelPayment(List<MerchantPaymentDto> merchantPaymentDtos) {
        merchantPaymentDtos.stream().forEach(merchantPaymentDto -> {
            // 异步执行
            channelPaymentGateway.submitChannelPayment(merchantPaymentDto);
            List<MerchantPaymentDetailDO> collect = merchantPaymentDto.getMerchantPaymentDetailList().stream()
                    .filter(merchantPaymentDetailDO -> MerchantEnum.PROCESS_STATUS.DOING.getCode().equals(merchantPaymentDetailDO.getStatus())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)) {
                merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
            }
            else {
                merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.FAIL.getCode());
            }
            merchantPaymentService.updatePayment(merchantPaymentDto);
        });
    }

    @Async("taskExecutor")
    void syncSubmitChannelPayment(MerchantPaymentDO merchantPayment, MerchantPaymentDetailDO paymentDetailDO) {
        MerchantPaymentDto merchantPaymentDto = BeanUtil.copyProperties(merchantPayment, MerchantPaymentDto.class);
        merchantPaymentDto.setMerchantPaymentDetailList(new ArrayList<>() {

            {
                add(paymentDetailDO);
            }
        });
        // 异步执行
        channelPaymentGateway.submitChannelPayment(merchantPaymentDto);
        merchantPaymentService.updatePaymentDetail(paymentDetailDO);
    }

    @Override
    public CommonResult<String> addFilePayment(MerchantPaymentFileReq merchantPaymentFileReq) {
        log.info("addPayment merchantPaymentFileReq:{}", JsonUtils.toJsonString(merchantPaymentFileReq));
        try {
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(merchantPaymentFileReq.getMchChannelCode());
            if (merchantAppChannelDO == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EXIST);
            }
            if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EFFECT);
            }
            if (!merchantPaymentFileReq.getFileUrl().endsWith(".xlsx")) {
                return CommonResult.error(CommonResultCode.FILE_ERROR);
            }
            MerchantInfoDO merchantInfoDO = merchantService.queryMerchant(merchantAppChannelDO.getSn());
            if (check) {
                if (!StringUtils.hasText(merchantInfoDO.getTranPwdEncrypt())) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_TRAN_PWD_NOT_EXIST);
                }
                String decryptString = aes256EncryptionProvider.encryptString(merchantPaymentFileReq.getTranPwd());
                if (!merchantInfoDO.getTranPwdEncrypt().equals(decryptString)) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_TRAN_PWD_ERROR);
                }
            }
            MerchantPaymentConfigDto merchantPaymentConfigDto = merchantConfigAppService.queryPaymentConfig(merchantAppChannelDO.getSn());

            // 获取远程文件输入流
            InputStream inputStream;
            if (merchantPaymentFileReq.getFileUrl().startsWith("http")) {
                URL url = new URL(merchantPaymentFileReq.getFileUrl());
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                // 设置请求方法和超时时间
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(10_000);
                connection.setReadTimeout(10_000);
                // 检查响应码
                int responseCode = connection.getResponseCode();
                if (responseCode != HttpURLConnection.HTTP_OK) {
                    return CommonResult.error(CommonResultCode.FILE_ERROR);
                }
                // 获取远程文件输入流
                inputStream = connection.getInputStream();
            }
            else if (merchantPaymentFileReq.getFileUrl().contains("secret")) {
                File file = new File(merchantPaymentFileReq.getFileUrl());
                inputStream = new FileInputStream(file);
            }
            else {
                return CommonResult.error(CommonResultCode.FILE_ERROR);
            }
            // 读取 Excel 数据为对象列表
            List<MerchantPaymentFileDto> merchantPaymentFileDtos = EasyExcel.read(inputStream).head(MerchantPaymentFileDto.class) // 指定模型类
                    .sheet() // 默认读取第一个 sheet
                    .doReadSync(); // 同步读取，返回结果
            List<MerchantPaymentDetailDO> merchantPaymentDetails = new ArrayList<>(merchantPaymentFileDtos.size() * 3 / 2);

            List<MerchantPaymentFileDto> errorFileList = new ArrayList<>();
            MerchantPaymentFileDto effectMerchantPaymentFileDto = null;
            for (MerchantPaymentFileDto merchantPaymentFileDto : merchantPaymentFileDtos) {
                String checkFileData = "";
                // if (merchantPaymentConfigDto != null && CollectionUtils.isNotEmpty(merchantPaymentConfigDto.getEntryTypes())
                //         && !merchantPaymentConfigDto.getEntryTypes().contains(merchantPaymentFileReq.getEntryType())) {
                //     checkFileData = OpenApiResultCode.MERCHANT_DATA_ERROR.getMsg();
                // }
                if (merchantPaymentConfigDto != null && CollectionUtils.isNotEmpty(merchantPaymentConfigDto.getEntryTypes())) {
                    List<MerchantPaymentConfigDto.EntryTypConfig> entryTypes = merchantPaymentConfigDto.getEntryTypes();
                    List<Integer> entryTypeList = entryTypes.stream().filter(entryType -> CommonEnum.YES_NO_TYPE.YES.getCode().equals(entryType.getStatus()))
                            .map(entryType -> entryType.getEntryType()).collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(entryTypeList)||!entryTypeList.contains(merchantPaymentFileReq.getEntryType())) {
                        return CommonResult.error(OpenApiResultCode.MERCHANT_DATA_ERROR);
                    }
                }
                else {
                    checkFileData = checkFileData(merchantPaymentFileDto, merchantPaymentFileReq.getEntryType());
                }
                if (StringUtils.hasText(checkFileData)) {
                    merchantPaymentFileDto.setErrorMsg(checkFileData);
                    errorFileList.add(merchantPaymentFileDto);
                }
                else {
                    effectMerchantPaymentFileDto = merchantPaymentFileDto;
                    MerchantPaymentDetailDO merchantPaymentDetailDO = BeanUtil.toBean(merchantPaymentFileDto, MerchantPaymentDetailDO.class);
                    merchantPaymentDetailDO.setFeePayer(CommonEnum.YES_NO_TYPE.YES.getCode());
                    merchantPaymentDetails.add(merchantPaymentDetailDO);
                }
            }
            // 前缀+yyyyMMddhhmmss+8 共1+14+8 共23位
            String paymentId = orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.PAYMENT_APPLY, 8);
            // 保存导入记录
            String errorFileUrl = processImportRecord(paymentId, merchantPaymentFileDtos.size(), merchantPaymentDetails.size(), errorFileList, merchantAppChannelDO.getSn(),
                    merchantPaymentFileReq.getFileUrl());
            if (CollectionUtils.isEmpty(merchantPaymentDetails)) {
                return CommonResult.error(CommonResultCode.FILE_ERROR.getCode(), "请查看错误文件," + errorFileUrl);
            }

            MerchantPaymentDto merchantPaymentDto = new MerchantPaymentDto();
            merchantPaymentDto.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDto.setProviderCode(merchantAppChannelDO.getProviderCode());
            merchantPaymentDto.setChannelCode(merchantAppChannelDO.getChannelCode());
            merchantPaymentDto.setAppId(merchantAppChannelDO.getAppId());
            merchantPaymentDto.setPaymentType(0);
            merchantPaymentDto.setPaymentId(paymentId);
            merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.INIT.getCode());
            merchantPaymentDto.setRemark(merchantPaymentFileReq.getRemark());
            merchantPaymentDto.setMchChannelCode(merchantPaymentFileReq.getMchChannelCode());
            if(merchantPaymentFileReq.getEntryType()==null){
                merchantPaymentFileReq.setEntryType(TransferOrderEnums.TRANSFER_ORDER_ENTRY_TYPE.BANK.getCode());
            }
            merchantPaymentDto.setEntryType(merchantPaymentFileReq.getEntryType());
            merchantPaymentDto.setPayeeType(effectMerchantPaymentFileDto.getPayeeType());

            PaymentCommonParamReq.Extra extra = new PaymentCommonParamReq.Extra();
            extra.setAccountType(2);
            merchantPaymentDto.setExtra(JsonUtils.toJsonString(extra));
            double sum = merchantPaymentDetails.stream().mapToDouble(merchantAppChannel -> merchantAppChannel.getPayAmount().doubleValue()).sum();
            merchantPaymentDto.setPayAmount(new BigDecimal(sum));
            merchantPaymentDto.setPayCount(merchantPaymentDetails.size());
            for (int i = 1; i <= merchantPaymentDetails.size(); i++) {
                MerchantPaymentDetailDO merchantPaymentDetailDO = merchantPaymentDetails.get(i - 1);
                merchantPaymentDetailDO.setPaymentId(merchantPaymentDto.getPaymentId());
                merchantPaymentDetailDO.setDetailPaymentId(merchantPaymentDetailDO.getPaymentId() + "_" + i);
                merchantPaymentDetailDO.setSn(merchantAppChannelDO.getSn());
                merchantPaymentDetailDO.setId(null);
            }
            merchantPaymentDto.setMerchantPaymentDetailList(merchantPaymentDetails);
            merchantPaymentService.addPayment(merchantPaymentDto);
            return CommonResult.success();
        }
        catch (ExcelCommonException e) {
            return CommonResult.error(CommonResultCode.FILE_ERROR);
        }
        catch (Exception e) {
            log.error("addPayment error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    String processImportRecord(String relationId, Integer totalCount, Integer successCount, List<MerchantPaymentFileDto> errorFileList, String sn, String importFileUrl) {
        ImportRecordDO importRecordDO = new ImportRecordDO();
        importRecordDO.setSn(sn);
        importRecordDO.setImportFileName("");
        importRecordDO.setImportFileUrl(importFileUrl);
        importRecordDO.setType(1);
        importRecordDO.setStatus(CommonEnum.YES_NO_TYPE.YES.getCode());
        importRecordDO.setTotalCount(totalCount);
        importRecordDO.setSuccessCount(successCount);
        importRecordDO.setFailCount(errorFileList.size());
        importRecordDO.setRelationId(relationId);
        try {
            if (CollectionUtils.isNotEmpty(errorFileList)) {
                // 创建输出流
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                // 使用 EasyExcel 写数据到流
                EasyExcel.write(outputStream, MerchantPaymentFileDto.class).sheet("代付错误信息") // 工作表名称
                        .doWrite(errorFileList); // 写入数据
                CommonResult<String> commonResult = uploadService.upload(outputStream.toByteArray(), CommonEnum.OssEnum.EXCEL);
                importRecordDO.setErrorFileUrl(commonResult.getData());
                importRecordDO.setErrorFileName("代付错误信息");
                // importRecordDO.setResultMessage();
            }
            importRecordService.addImportRecord(importRecordDO);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return importRecordDO.getErrorFileUrl();
    }

    String checkFileData(MerchantPaymentFileDto merchantPaymentFileDto, Integer entryType) {
        StringBuilder sb = new StringBuilder();
        if (merchantPaymentFileDto.getPayeeType() == null) {
            if (entryType != null && (entryType == 3 || entryType == 4)) {
                sb.append("收款方类型为空");
                sb.append(";");
            }
        }
        else if (merchantPaymentFileDto.getPayeeType() > 2 || merchantPaymentFileDto.getPayeeType() < 1) {
            sb.append("收款方类型无效");
            sb.append(";");
        }
        if (merchantPaymentFileDto.getPayAmount() == null) {
            sb.append("下发金额为空");
            sb.append(";");
        }
        if (StringUtils.isEmpty(merchantPaymentFileDto.getName())) {
            sb.append("收款方姓名为空");
            sb.append(";");
        }
        if (StringUtils.isEmpty(merchantPaymentFileDto.getCardNo())) {
            sb.append("收款人账号为空");
            sb.append(";");
        }
        else if (containsChinese(merchantPaymentFileDto.getCardNo())) {
            sb.append("收款人账号格式错误");
            sb.append(";");
        }
        // if (StringUtils.isEmpty(merchantPaymentFileDto.getBankName())) {
        // sb.append("银行名称为空");
        // sb.append(";");
        // }
        if (!StringUtils.isEmpty(merchantPaymentFileDto.getBankCode()) && containsChinese(merchantPaymentFileDto.getBankCode())) {
            sb.append("银行编码格式错误");
            sb.append(";");
        }
        if (!StringUtils.isEmpty(merchantPaymentFileDto.getBranchCode()) && containsChinese(merchantPaymentFileDto.getBranchCode())) {
            sb.append("联行号格式错误");
            sb.append(";");
        }
        if (!StringUtils.isEmpty(merchantPaymentFileDto.getCardPhone()) && !isValidPhoneNumber(merchantPaymentFileDto.getCardPhone())) {
            sb.append("银行卡绑定手机号格式错误");
            sb.append(";");
        }
        return sb.toString();
    }

    public static boolean containsChinese(String str) {
        // 正则表达式：匹配中文字符的 Unicode 范围
        String regex = "[\u4e00-\u9fa5]";
        return str.matches(".*" + regex + ".*");
    }

    public static boolean isValidPhoneNumber(String phoneNumber) {
        // 正则表达式：以1开头，第二位是3-9之间的数字，后面是9个数字
        String regex = "^1[3-9]\\d{9}$";
        return phoneNumber.matches(regex);
    }

    @Override
    public CommonResult<Void> addPayment(MerchantPaymentDetailReq merchantPaymentDetailReq) {
        log.info("addPayment merchantPaymentDetailReq:{}", JsonUtils.toJsonString(merchantPaymentDetailReq));
        try {
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(merchantPaymentDetailReq.getMchChannelCode());
            if (merchantAppChannelDO == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_CHANNEL_NOT_EXIST);
            }
            if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EFFECT);
            }
            MerchantInfoDO merchantInfoDO = merchantService.queryMerchant(merchantAppChannelDO.getSn());
            if (check) {
                if (!StringUtils.hasText(merchantInfoDO.getTranPwdEncrypt())) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_TRAN_PWD_NOT_EXIST);
                }
                String decryptString = aes256EncryptionProvider.encryptString(merchantPaymentDetailReq.getTranPwd());
                if (!merchantInfoDO.getTranPwdEncrypt().equals(decryptString)) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_TRAN_PWD_ERROR);
                }
            }
            MerchantPaymentConfigDto merchantPaymentConfigDto = merchantConfigAppService.queryPaymentConfig(merchantAppChannelDO.getSn());
            if (merchantPaymentConfigDto != null && CollectionUtils.isNotEmpty(merchantPaymentConfigDto.getEntryTypes())) {
                List<MerchantPaymentConfigDto.EntryTypConfig> entryTypes = merchantPaymentConfigDto.getEntryTypes();
                // log.info("tets:{}",JsonUtils.toJsonString(entryTypes));
                List<Integer> entryTypeList = entryTypes.stream().filter(entryTypConfig -> CommonEnum.YES_NO_TYPE.YES.getCode().equals(entryTypConfig.getStatus()))
                        .map(entryTypConfig -> entryTypConfig.getEntryType()).collect(Collectors.toList());
                // log.info("tets:{}",JsonUtils.toJsonString(entryTypeList));
                if (CollectionUtils.isEmpty(entryTypeList)||!entryTypeList.contains(merchantPaymentDetailReq.getEntryType())) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_DATA_ERROR);
                }
            }
            String paymentId = orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.PAYMENT_APPLY, 8);
            MerchantPaymentDto merchantPaymentDto = new MerchantPaymentDto();
            merchantPaymentDto.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDto.setProviderCode(merchantAppChannelDO.getProviderCode());
            merchantPaymentDto.setChannelCode(merchantAppChannelDO.getChannelCode());
            merchantPaymentDto.setAppId(merchantAppChannelDO.getAppId());
            merchantPaymentDto.setMchChannelCode(merchantPaymentDetailReq.getMchChannelCode());
            merchantPaymentDto.setPaymentId(paymentId);
            merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.INIT.getCode());
            merchantPaymentDto.setPayAmount(merchantPaymentDetailReq.getPayAmount());
            merchantPaymentDto.setPayCount(1);
            merchantPaymentDto.setRemark(merchantPaymentDetailReq.getRemark());
            merchantPaymentDto.setPaymentType(merchantPaymentDetailReq.getPaymentType());
            merchantPaymentDto.setPayeeType(merchantPaymentDetailReq.getPayeeType());
            merchantPaymentDto.setEntryType(merchantPaymentDetailReq.getEntryType());
            PaymentCommonParamReq.Extra extra = new PaymentCommonParamReq.Extra();
            extra.setAccountType(2);
            merchantPaymentDto.setExtra(JsonUtils.toJsonString(extra));
            MerchantPaymentDetailDO merchantPaymentDetailDO = BeanUtil.copyProperties(merchantPaymentDetailReq, MerchantPaymentDetailDO.class);
            merchantPaymentDetailDO.setPaymentId(merchantPaymentDto.getPaymentId());
            merchantPaymentDetailDO.setDetailPaymentId(paymentId + "_1");
            merchantPaymentDetailDO.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDto.setMerchantPaymentDetailList(List.of(merchantPaymentDetailDO));
            merchantPaymentService.addPayment(merchantPaymentDto);
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("addPayment error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Set<String>> addReportPayment(MerchantAppChannelDO merchantAppChannelDO, BigDecimal totalAmount,
            List<MerchantPaymentConfigMappingDto> merchantReportPaymentConfigList) {
        log.info("addReportPayment merchantPaymentDetailReq:{}", JsonUtils.toJsonString(merchantReportPaymentConfigList));
        try {
            if (merchantAppChannelDO == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EXIST);
            }
            if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EFFECT);
            }
            Map<String, List<MerchantPaymentConfigMappingDto>> merchantReportPaymentConfigMap = merchantReportPaymentConfigList.stream().collect(
                    Collectors.groupingBy(merchantReportPaymentConfigDO -> merchantReportPaymentConfigDO.getEntryType() + "_" + merchantReportPaymentConfigDO.getPayeeType()));
            List<MerchantPaymentDto> merchantPaymentDtos = new ArrayList<>();
            Set<String> paymentIds = new HashSet<>();
            merchantReportPaymentConfigMap.forEach((key, value) -> {
                MerchantPaymentConfigMappingDto reportPaymentConfigDO = value.get(0);
                String paymentId = orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.PAYMENT_APPLY, 8);
                paymentIds.add(paymentId);
                MerchantPaymentDto merchantPaymentDto = new MerchantPaymentDto();
                merchantPaymentDto.setSn(merchantAppChannelDO.getSn());
                merchantPaymentDto.setProviderCode(merchantAppChannelDO.getProviderCode());
                merchantPaymentDto.setChannelCode(merchantAppChannelDO.getChannelCode());
                merchantPaymentDto.setAppId(merchantAppChannelDO.getAppId());
                merchantPaymentDto.setMchChannelCode(merchantAppChannelDO.getCode());
                merchantPaymentDto.setPaymentId(paymentId);
                merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());

                merchantPaymentDto.setPayCount(value.size());
                // merchantPaymentDto.setRemark();
                merchantPaymentDto.setPaymentType(CommonEnum.YES_NO_TYPE.NO.getCode());
                merchantPaymentDto.setPayeeType(reportPaymentConfigDO.getPayeeType());
                merchantPaymentDto.setEntryType(reportPaymentConfigDO.getEntryType());
                int size = 1;
                List<MerchantPaymentDetailDO> merchantPaymentDetailList = new ArrayList<>();
                for (MerchantPaymentConfigMappingDto merchantPaymentAccountConfigDO : value) {
                    PaymentCommonParamReq.Extra extra = new PaymentCommonParamReq.Extra();
                    extra.setAccountType(2);
                    merchantPaymentDto.setExtra(JsonUtils.toJsonString(extra));
                    MerchantPaymentDetailDO merchantPaymentDetailDO = BeanUtil.copyProperties(merchantPaymentAccountConfigDO, MerchantPaymentDetailDO.class);
                    merchantPaymentDetailDO.setPaymentId(merchantPaymentDto.getPaymentId());
                    merchantPaymentDetailDO.setDetailPaymentId(paymentId + "_" + size);

                    merchantPaymentDetailDO.setPayAmount(MerchantUtils.multiply(totalAmount, merchantPaymentAccountConfigDO.getPayAmount().multiply(new BigDecimal(100))));
                    merchantPaymentDetailDO.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
                    merchantPaymentDetailDO.setId(null);
                    size = size + 1;
                    merchantPaymentDetailDO.setSn(merchantAppChannelDO.getSn());
                    merchantPaymentDetailList.add(merchantPaymentDetailDO);
                }
                double summed = merchantPaymentDetailList.stream().mapToDouble(merchantPaymentDetailDO -> merchantPaymentDetailDO.getPayAmount().doubleValue()).sum();
                merchantPaymentDto.setPayAmount(new BigDecimal(summed));
                merchantPaymentDto.setMerchantPaymentDetailList(merchantPaymentDetailList);
                merchantPaymentDtos.add(merchantPaymentDto);
            });
            merchantPaymentService.addPaymentList(merchantPaymentDtos);
            syncSubmitChannelPayment(merchantPaymentDtos);
            return CommonResult.success(paymentIds);
        }
        catch (Exception e) {
            log.error("addPayment error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> updatePayment(MerchantPaymentDetailUpdateReq merchantPaymentDetailUpdateReq) {
        log.info("updatePayment merchantPaymentDetailUpdateReq:{}", JsonUtils.toJsonString(merchantPaymentDetailUpdateReq));
        try {
            MerchantPaymentDetailDO merchantPaymentDetailDO = merchantPaymentService.queryPaymentDetail(merchantPaymentDetailUpdateReq.getDetailPaymentId());
            if (merchantPaymentDetailDO == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_NOT_EXIST);
            }
            MerchantPaymentDetailDO updateMerchantPaymentDetailDO = BeanUtil.copyProperties(merchantPaymentDetailUpdateReq, MerchantPaymentDetailDO.class);
            updateMerchantPaymentDetailDO.setId(merchantPaymentDetailDO.getId());
            updateMerchantPaymentDetailDO.setRemark("");
            merchantPaymentService.updatePaymentDetail(updateMerchantPaymentDetailDO);
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("addPayment error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<List<MerchantAcctBalanceDto>> queryAccount(String mchChannelCode, List<Integer> acctTypeList) {
        if (CollectionUtils.isEmpty(acctTypeList)) {
            acctTypeList = new ArrayList<>();
            acctTypeList.add(1);
            acctTypeList.add(2);
            acctTypeList.add(3);
        }
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(mchChannelCode);
        if (merchantAppChannelDO == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EXIST);
        }
        // if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
        //     return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EFFECT);
        // }
        boolean extensionExist = channelPaymentGateway.extensionExist(mchChannelCode);
        if (!extensionExist) {
            return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
        }
        List<MerchantAcctBalanceDto> merchantAcctBalances = channelPaymentGateway.queryChannelPaymentAccount(mchChannelCode, acctTypeList);
        return CommonResult.success(merchantAcctBalances);
    }

    @Override
    public List<MerchantPaymentDetailDO> queryDetailList(String paymentId) {
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(paymentId);
        merchantPaymentDto.getMerchantPaymentDetailList().stream().forEach(merchantPaymentDetailDO -> {
            if (MerchantEnum.PROCESS_STATUS.DOING.getCode().equals(merchantPaymentDetailDO.getStatus())) {
                boolean extensionExist = channelPaymentGateway.extensionExist(merchantPaymentDto.getMchChannelCode());
                if (extensionExist) {
                    MerchantPaymentQueryDto merchantPaymentQueryDto = new MerchantPaymentQueryDto();
                    merchantPaymentQueryDto.setMerchantPaymentDO(merchantPaymentDto);
                    merchantPaymentQueryDto.setMerchantPaymentDetail(merchantPaymentDetailDO);
                    MerchantPaymentDetailDO merchantPaymentDetailQuery = channelPaymentGateway.queryChannelPaymentDetail(merchantPaymentQueryDto);
                    log.info("代付日志  queryDetailList {}", paymentId);
                    updatePayOrder(merchantPaymentDetailQuery, merchantPaymentDetailDO);
                }
            }
        });
        List<MerchantPaymentDetailDO> merchantPaymentDetailList = merchantPaymentService.queryDetailList(paymentId, MerchantEnum.PROCESS_STATUS.DOING.getCode());
        if (CollectionUtils.isEmpty(merchantPaymentDetailList)) {
            merchantPaymentService.updatePaymentStatus(paymentId, MerchantEnum.PROCESS_STATUS.SUCCESS);
        }
        return merchantPaymentDto.getMerchantPaymentDetailList();
    }

    @Override
    public CommonResult<Void> syncDetailStatus(String detailPaymentId) {
        MerchantPaymentDetailDO merchantPaymentDetailDO = merchantPaymentService.queryPaymentDetail(detailPaymentId);
        if (!MerchantEnum.PROCESS_STATUS.DOING.getCode().equals(merchantPaymentDetailDO.getStatus())) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_CANNOT_SYNC);
        }
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(merchantPaymentDetailDO.getPaymentId());
        boolean extensionExist = channelPaymentGateway.extensionExist(merchantPaymentDto.getMchChannelCode());
        if (extensionExist) {
            MerchantPaymentQueryDto merchantPaymentQueryDto = new MerchantPaymentQueryDto();
            merchantPaymentQueryDto.setMerchantPaymentDO(merchantPaymentDto);
            merchantPaymentQueryDto.setMerchantPaymentDetail(merchantPaymentDetailDO);

            MerchantPaymentDetailDO merchantPaymentDetailQuery = channelPaymentGateway.queryChannelPaymentDetail(merchantPaymentQueryDto);
            if (merchantPaymentDetailQuery.getStatus() != null) {
                if (!merchantPaymentDetailQuery.getStatus().equals(merchantPaymentDetailDO.getStatus())) {
                    log.info("代付日志  syncDetailStatus id {} , status {}", merchantPaymentDetailDO.getDetailPaymentId(), merchantPaymentDetailDO.getStatus());
                    updatePayOrder(merchantPaymentDetailQuery, merchantPaymentDetailDO);
                }
                List<MerchantPaymentDetailDO> merchantPaymentDetailList = merchantPaymentService.queryDetailList(merchantPaymentDetailDO.getPaymentId(),
                        MerchantEnum.PROCESS_STATUS.DOING.getCode());
                if (CollectionUtils.isEmpty(merchantPaymentDetailList)) {
                    merchantPaymentService.updatePaymentStatus(merchantPaymentDetailDO.getPaymentId(), MerchantEnum.PROCESS_STATUS.SUCCESS);
                }
            }
        }
        return CommonResult.success();
    }

    @Override
    @Async("taskExecutor")
    public void syncAll(List<MerchantPaymentPageDto> merchantPaymentDetailDtos) {
        log.info("用户列表查询触发 代付状态同步");
        List<MerchantPaymentPageDto> merchantPaymentPageDtos = merchantPaymentDetailDtos.stream()
                .filter(merchantPaymentDetailDto -> MerchantEnum.PROCESS_STATUS.DOING.getCode().equals(merchantPaymentDetailDto.getStatus())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(merchantPaymentPageDtos)) {
            return;
        }
        for (MerchantPaymentPageDto merchantPaymentPageDto : merchantPaymentPageDtos) {
            queryDetailList(merchantPaymentPageDto.getPaymentId());
        }
    }

    @Override
    public CommonResult<Void> submitDetail(MerchantPaymentDetailPageResp merchantPaymentDetailPageResp) {
        MerchantPaymentDetailDO merchantPaymentDetailDO = merchantPaymentService.queryPaymentDetail(merchantPaymentDetailPageResp.getDetailPaymentId());
        if (merchantPaymentDetailDO == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_NOT_EXIST);
        }
        if (!MerchantEnum.PROCESS_STATUS.FAIL.getCode().equals(merchantPaymentDetailDO.getStatus())) {
            return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
        }
        MerchantPaymentDetailDO paymentDetailDO = BeanUtil.copyProperties(merchantPaymentDetailPageResp, MerchantPaymentDetailDO.class);
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(merchantPaymentDetailDO.getPaymentId());
        MerchantPaymentDO merchantPaymentDO = new MerchantPaymentDO();
        merchantPaymentDO.setId(merchantPaymentDto.getId());
        merchantPaymentDO.setPayCount(merchantPaymentDto.getPayCount() + 1);
        merchantPaymentDO.setPayAmount(merchantPaymentDto.getPayAmount().add(paymentDetailDO.getPayAmount()));
        paymentDetailDO.setDetailPaymentId(merchantPaymentDto.getPaymentId() + "_" + merchantPaymentDO.getPayCount());
        merchantPaymentService.updatePayment(merchantPaymentDO);
        paymentDetailDO.setId(null);
        paymentDetailDO.setRemark("");
        paymentDetailDO.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
        merchantPaymentService.addPaymentDetail(paymentDetailDO);
        syncSubmitChannelPayment(merchantPaymentDto, paymentDetailDO);
        return CommonResult.success();
    }

    @Override
    public CommonResult<PaymentApiResp> submitOpenapi(@Valid PaymentCommonParamReq paymentCommonParamReq) {
        log.info("submitOpenapi merchantPaymentDetailReq:{}", JsonUtils.toJsonString(paymentCommonParamReq));

        // 获取锁
        RLock rLock = redisTemplateService.getLock("payment:submitOpenapi:"+paymentCommonParamReq.getMchOrderNo());
        try {
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(paymentCommonParamReq.getMchChannelCode());
            if (merchantAppChannelDO == null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_APP_NOT_EXIST);
            }
            if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_APP_NOT_EFFECT);
            }
            // 获取锁成功，处理业务
            if (!rLock.tryLock(0,30, TimeUnit.SECONDS)) {
                log.info("submitOpenapi tryLock fail, payment:{}", JSONUtil.toJsonStr(paymentCommonParamReq));
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_EXIST);
            }

            MerchantPaymentDetailDO merchantPaymentDetailDb = merchantPaymentService.queryPaymentDetailByMchOrder(paymentCommonParamReq.getMchOrderNo());
            if (merchantPaymentDetailDb != null) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_EXIST);
            }
            MerchantPaymentConfigDto merchantPaymentConfigDto = merchantConfigAppService.queryPaymentConfig(merchantAppChannelDO.getSn());
            // if (merchantPaymentConfigDto != null && CollectionUtils.isNotEmpty(merchantPaymentConfigDto.getEntryTypes())
            //         && !merchantPaymentConfigDto.getEntryTypes().contains(paymentCommonParamReq.getEntryType())) {
            //     return CommonResult.error(OpenApiResultCode.MERCHANT_DATA_ERROR);
            // }
            if (merchantPaymentConfigDto != null && CollectionUtils.isNotEmpty(merchantPaymentConfigDto.getEntryTypes())) {
                List<MerchantPaymentConfigDto.EntryTypConfig> entryTypes = merchantPaymentConfigDto.getEntryTypes();
                List<Integer> entryTypeList = entryTypes.stream().filter(entryType -> CommonEnum.YES_NO_TYPE.YES.getCode().equals(entryType.getStatus()))
                        .map(entryType -> entryType.getEntryType()).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(entryTypeList)||!entryTypeList.contains(paymentCommonParamReq.getEntryType())) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_DATA_ERROR);
                }
            }

            String paymentId = orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.PAYMENT_APPLY, 8);
            MerchantPaymentDto merchantPaymentDto = new MerchantPaymentDto();
            merchantPaymentDto.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDto.setProviderCode(merchantAppChannelDO.getProviderCode());
            merchantPaymentDto.setChannelCode(merchantAppChannelDO.getChannelCode());
            merchantPaymentDto.setAppId(merchantAppChannelDO.getAppId());
            merchantPaymentDto.setMchChannelCode(paymentCommonParamReq.getMchChannelCode());
            merchantPaymentDto.setPaymentId(paymentId);
            merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.APPROVE.getCode());
            merchantPaymentDto.setRemark(paymentCommonParamReq.getRemark());
            merchantPaymentDto.setPayAmount(MerchantUtils.stringToBigDecimal(paymentCommonParamReq.getAmount()));
            merchantPaymentDto.setEntryType(paymentCommonParamReq.getEntryType());
            merchantPaymentDto.setClientIp(paymentCommonParamReq.getClientIp());
            merchantPaymentDto.setExtra(JsonUtils.toJsonString(paymentCommonParamReq.getExtra()));
            merchantPaymentDto.setNotifyUrl(paymentCommonParamReq.getNotifyUrl());
            LocalMerchantRequest request = (LocalMerchantRequest) LocalContext.get();
            merchantPaymentDto.setSignType(request.getSignType());
            merchantPaymentDto.setPayCount(1);
            merchantPaymentDto.setPayeeType(paymentCommonParamReq.getPayeeType());
            MerchantPaymentDetailDO merchantPaymentDetailDO = new MerchantPaymentDetailDO();
            merchantPaymentDetailDO.setStatus(MerchantEnum.PROCESS_STATUS.INIT.getCode());
            merchantPaymentDetailDO.setPayAmount(merchantPaymentDto.getPayAmount());
            merchantPaymentDetailDO.setName(paymentCommonParamReq.getName());
            merchantPaymentDetailDO.setCardNo(paymentCommonParamReq.getCardNo());
            merchantPaymentDetailDO.setBankCode(paymentCommonParamReq.getBankCode());
            merchantPaymentDetailDO.setBankName(paymentCommonParamReq.getBankName());
            merchantPaymentDetailDO.setBranchCode(paymentCommonParamReq.getBranchCode());
            merchantPaymentDetailDO.setFeePayer(1);
            merchantPaymentDetailDO.setPaymentId(merchantPaymentDto.getPaymentId());
            merchantPaymentDetailDO.setDetailPaymentId(paymentId + "_1");
            merchantPaymentDetailDO.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDetailDO.setMchOrderNo(paymentCommonParamReq.getMchOrderNo());
            merchantPaymentDto.setMerchantPaymentDetailList(List.of(merchantPaymentDetailDO));
            merchantPaymentService.addPayment(merchantPaymentDto);
            syncSubmitChannelPayment(merchantPaymentDto, merchantPaymentDetailDO);
            // 保存后自动审核
            return CommonResult.success(OpenApiParamsUtils.paymentApiResp(merchantPaymentDto, merchantPaymentDetailDO));
        }
        catch (Exception e) {
            log.error("addPayment error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        } finally {
            //释放锁
            rLock.forceUnlock();
        }
    }

    @Override
    public CommonResult<PaymentApiResp> queryOpenApiDetail(PayOrderQueryReq payOrderQueryReq) {
        MerchantPaymentDetailDO merchantPaymentDetailDO;
        if (!StringUtils.hasText(payOrderQueryReq.getPayOrderNo()) && !StringUtils.hasText(payOrderQueryReq.getMchOrderNo())) {
            return CommonResult.error(CommonResultCode.PARAMETER_ERROR);
        }
        if (StringUtils.hasText(payOrderQueryReq.getPayOrderNo())) {
            merchantPaymentDetailDO = merchantPaymentService.queryPaymentDetail(payOrderQueryReq.getPayOrderNo());
        }
        else {
            merchantPaymentDetailDO = merchantPaymentService.queryPaymentDetailByMchOrder(payOrderQueryReq.getMchOrderNo());
        }
        if (merchantPaymentDetailDO == null) {
            return CommonResult.error(CommonResultCode.DATA_NOT_EXIST);
        }
        MerchantPaymentDO merchantPaymentDO = merchantPaymentService.queryDetail(merchantPaymentDetailDO.getPaymentId());
        return CommonResult.success(OpenApiParamsUtils.paymentApiResp(merchantPaymentDO, merchantPaymentDetailDO));
    }

    @Override
    public CommonResult<String> queryProof(String paymentId, boolean regenerate) {
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(paymentId);
        if (merchantPaymentDto == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_NOT_EXIST);
        }
        if (StringUtils.hasText(merchantPaymentDto.getProofPath()) && !regenerate) {
            return CommonResult.success(domain + merchantPaymentDto.getProofPath().replace(uploadDirectory, uploadHidden));
        }
        List<MerchantPaymentDetailDO> merchantPaymentDetailList = merchantPaymentDto.getMerchantPaymentDetailList();
        List<MerchantPaymentDetailDO> paymentDetailList = merchantPaymentDetailList.stream()
                .filter(merchantPaymentDetailDO -> MerchantEnum.PROCESS_STATUS.SUCCESS.getCode().equals(merchantPaymentDetailDO.getStatus())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(paymentDetailList)) {
            log.info("当前代付不存在执行成功明细,无非查看凭证:{}", paymentId);
            return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_NOT_SUCCESS);
        }
        boolean extensionExist = channelPaymentGateway.extensionExist(merchantPaymentDto.getMchChannelCode());
        if (!extensionExist) {
            return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
        }
        regenerateFile(merchantPaymentDto, paymentDetailList);
        return CommonResult.success();
    }

    @Async("taskExecutor")
    public void regenerateFile(MerchantPaymentDto merchantPaymentDto, List<MerchantPaymentDetailDO> paymentDetailList) {
        log.info("异步生生成代付文件 代付状态同步");
        List<MerchantPaymentDetailDO> waitProofPaymentDetailList = paymentDetailList.stream()
                .filter(merchantPaymentDetailDO -> !StringUtils.hasText(merchantPaymentDetailDO.getProofPath())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(waitProofPaymentDetailList)) {
            waitProofPaymentDetailList.stream().forEach(waitProofPaymentDetail -> {
                processProof(merchantPaymentDto.getMchChannelCode(), waitProofPaymentDetail);
            });
        }
        List<String> fileList = paymentDetailList.stream().map(paymentDetail -> paymentDetail.getProofPath()).collect(Collectors.toList());
        // 生成一个zip
        CommonResult<String> stringCommonResult = uploadService.uploadLocalFileZip(fileList, merchantPaymentDto.getPaymentId());
        if (stringCommonResult.isSuccess()) {
            MerchantPaymentDO merchantPaymentDO = new MerchantPaymentDO();
            merchantPaymentDO.setId(merchantPaymentDto.getId());
            merchantPaymentDO.setProofPath(stringCommonResult.getData());
            merchantPaymentService.updatePayment(merchantPaymentDO);
        }
    }

    @Override
    public CommonResult<String> queryDetailProof(String detailPaymentId) {
        MerchantPaymentDetailDO merchantPaymentDetailDO = merchantPaymentService.queryPaymentDetail(detailPaymentId);
        if (merchantPaymentDetailDO == null || !MerchantEnum.PROCESS_STATUS.SUCCESS.getCode().equals(merchantPaymentDetailDO.getStatus())) {
            log.info("当前代付非执行成功,无非查看凭证:{}", detailPaymentId);
            return CommonResult.error(MerchantResultCode.MERCHANT_PAYMENT_NOT_SUCCESS);
        }
        if (StringUtils.hasText(merchantPaymentDetailDO.getProofPath())) {
            return CommonResult.success(domain + merchantPaymentDetailDO.getProofPath().replace(uploadDirectory, uploadHidden));
        }
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(merchantPaymentDetailDO.getPaymentId());
        boolean extensionExist = channelPaymentGateway.extensionExist(merchantPaymentDto.getMchChannelCode());
        if (!extensionExist) {
            return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
        }
        return processProof(merchantPaymentDto.getMchChannelCode(), merchantPaymentDetailDO);

    }

    @Override
    public String orderStatusCallBack(String paymentId, HttpServletRequest servletRequest) {
        // String accessCallBody = HttpRequestUtil.requestParams(servletRequest);
        log.info("收到代付回调 paymentId:{} ", paymentId);
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(paymentId);
        ChannelPaymentCallBackDto channelPaymentCallBackDto = channelPaymentGateway.parseCallBackText(merchantPaymentDto.getMchChannelCode(), servletRequest);
        MerchantPaymentDetailDO merchantPaymentDetailDO = channelPaymentCallBackDto.getMerchantPaymentDetailDO();
        if (channelPaymentCallBackDto.isProcessStatus()) {
            if (channelPaymentCallBackDto.isVerifySign()) {
                if (merchantPaymentDetailDO.getStatus() != null) {
                    // merchantPaymentService.updatePaymentDetail(channelPaymentCallBackDto);
                    MerchantPaymentDetailDO merchantPaymentDb = merchantPaymentService.queryPaymentDetail(merchantPaymentDetailDO.getDetailPaymentId());
                    log.info("代付日志  orderStatusCallBack id {} status {}", merchantPaymentDetailDO.getDetailPaymentId(), merchantPaymentDetailDO.getStatus());
                    updatePayOrder(merchantPaymentDetailDO, merchantPaymentDb);
                    List<MerchantPaymentDetailDO> merchantPaymentDetailList = merchantPaymentService.queryDetailList(paymentId, MerchantEnum.PROCESS_STATUS.DOING.getCode());
                    if (CollectionUtils.isEmpty(merchantPaymentDetailList)) {
                        merchantPaymentService.updatePaymentStatus(paymentId, MerchantEnum.PROCESS_STATUS.SUCCESS);
                    }
                }
            }
            else {
                MerchantPaymentDetailDO merchantPaymentDb = merchantPaymentService.queryPaymentDetail(merchantPaymentDetailDO.getDetailPaymentId());
                MerchantPaymentQueryDto merchantPaymentQueryDto = new MerchantPaymentQueryDto();
                merchantPaymentQueryDto.setMerchantPaymentDO(merchantPaymentDto);
                merchantPaymentQueryDto.setMerchantPaymentDetail(merchantPaymentDetailDO);
                log.info("回调验签错误,发起主动查询 detailPaymentId:{}", merchantPaymentDetailDO.getDetailPaymentId());
                MerchantPaymentDetailDO merchantPaymentDetailQuery = channelPaymentGateway.queryChannelPaymentDetail(merchantPaymentQueryDto);
                updatePayOrder(merchantPaymentDetailQuery, merchantPaymentDb);
            }
        }

        return channelPaymentGateway.processCallBack(merchantPaymentDto.getMchChannelCode(), CommonResult.success());
    }

    @Override
    public String orderStatusFixCallBack(String channelCode, HttpServletRequest servletRequest) {
        // String accessCallBody = HttpRequestUtil.requestParams(servletRequest);
        log.info("收到代付回调 channelCode:{}", channelCode);
        ChannelPaymentCallBackDto channelPaymentCallBackDto = channelPaymentGateway.parseCallBackTextFix(channelCode, servletRequest);
        MerchantPaymentDetailDO merchantPaymentDetailDO = channelPaymentCallBackDto.getMerchantPaymentDetailDO();
        if (!StringUtils.hasText(merchantPaymentDetailDO.getDetailPaymentId())) {
            return "fail";
        }
        MerchantPaymentDetailDO merchantPaymentDb = merchantPaymentService.queryPaymentDetail(merchantPaymentDetailDO.getDetailPaymentId());
        if (merchantPaymentDb == null) {
            return "fail";
        }
        MerchantPaymentDto merchantPaymentDto = merchantPaymentService.queryDetailDto(merchantPaymentDb.getPaymentId());
        boolean verify = channelPaymentGateway.verify(merchantPaymentDto.getMchChannelCode(), channelPaymentCallBackDto.getRequestParams());
        if (verify) {
            if (merchantPaymentDetailDO.getStatus() != null) {
                log.info("代付日志  orderStatusFixCallBack merchantPaymentDetailDO id {}, status {}", merchantPaymentDetailDO.getDetailPaymentId(), merchantPaymentDetailDO.getStatus());
                log.info("代付日志  orderStatusFixCallBack merchantPaymentDb id {}, status {}", merchantPaymentDb.getDetailPaymentId(), merchantPaymentDb.getStatus());
                updatePayOrder(merchantPaymentDetailDO, merchantPaymentDb);
                List<MerchantPaymentDetailDO> merchantPaymentDetailList = merchantPaymentService.queryDetailList(merchantPaymentDb.getPaymentId(),
                        MerchantEnum.PROCESS_STATUS.DOING.getCode());
                if (CollectionUtils.isEmpty(merchantPaymentDetailList)) {
                    merchantPaymentService.updatePaymentStatus(merchantPaymentDb.getPaymentId(), MerchantEnum.PROCESS_STATUS.SUCCESS);
                }
            }
        }
        else {
            MerchantPaymentQueryDto merchantPaymentQueryDto = new MerchantPaymentQueryDto();
            merchantPaymentQueryDto.setMerchantPaymentDO(merchantPaymentDto);
            merchantPaymentQueryDto.setMerchantPaymentDetail(merchantPaymentDetailDO);

            log.info("回调验签错误,发起主动查询 detailPaymentId:{}", merchantPaymentDetailDO.getDetailPaymentId());
            MerchantPaymentDetailDO merchantPaymentDetailQuery = channelPaymentGateway.queryChannelPaymentDetail(merchantPaymentQueryDto);
            updatePayOrder(merchantPaymentDetailQuery, merchantPaymentDb);
        }
        return channelPaymentGateway.processCallBack(merchantPaymentDto.getMchChannelCode(), CommonResult.success());
    }

    @Override
    public CommonResult<String> addRecharge(MerchantPaymentDetailReq merchantPaymentDetailReq) {
        log.info("addRecharge merchantPaymentDetailReq:{}", JsonUtils.toJsonString(merchantPaymentDetailReq));
        try {
            MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(merchantPaymentDetailReq.getMchChannelCode());
            if (merchantAppChannelDO == null) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EXIST);
            }
            if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(merchantAppChannelDO.getStatus())) {
                return CommonResult.error(MerchantResultCode.MERCHANT_APP_NOT_EFFECT);
            }
            String paymentId = orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.PAYMENT_APPLY, 8);
            MerchantPaymentDto merchantPaymentDto = new MerchantPaymentDto();
            merchantPaymentDto.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDto.setProviderCode(merchantAppChannelDO.getProviderCode());
            merchantPaymentDto.setChannelCode(merchantAppChannelDO.getChannelCode());
            merchantPaymentDto.setAppId(merchantAppChannelDO.getAppId());
            merchantPaymentDto.setMchChannelCode(merchantPaymentDetailReq.getMchChannelCode());
            merchantPaymentDto.setPaymentId(paymentId);
            merchantPaymentDto.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
            merchantPaymentDto.setPayAmount(merchantPaymentDetailReq.getPayAmount());
            merchantPaymentDto.setPayCount(1);
            merchantPaymentDto.setRemark(merchantPaymentDetailReq.getRemark());
            merchantPaymentDto.setPaymentType(CommonEnum.YES_NO_TYPE.YES.getCode());
            MerchantPaymentDetailDO merchantPaymentDetailDO = BeanUtil.copyProperties(merchantPaymentDetailReq, MerchantPaymentDetailDO.class);
            merchantPaymentDetailDO.setPaymentId(merchantPaymentDto.getPaymentId());
            merchantPaymentDetailDO.setDetailPaymentId(paymentId + "_1");
            merchantPaymentDetailDO.setSn(merchantAppChannelDO.getSn());
            merchantPaymentDetailDO.setStatus(MerchantEnum.PROCESS_STATUS.DOING.getCode());
            merchantPaymentDto.setMerchantPaymentDetailList(List.of(merchantPaymentDetailDO));
            merchantPaymentService.addPayment(merchantPaymentDto);
            String url = channelPaymentGateway.submitChannelRecharge(merchantPaymentDto, merchantPaymentDetailDO);
            return CommonResult.success(url);
        }
        catch (Exception e) {
            log.error("addPayment error:{}", e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }
    @Override
    public void notifyChannel(MerchantPaymentDO merchantPaymentDO, MerchantPaymentDetailDO merchantPaymentDetailDO) {
        // 渠道用户通知
        channelPaymentGateway.notifyChannel(merchantPaymentDO, merchantPaymentDetailDO);
        // 凭证生成
        channelPaymentGateway.notifyProofGenerate(merchantPaymentDO, merchantPaymentDetailDO);
        if (StringUtils.hasText(merchantPaymentDetailDO.getProofId())) {
            MerchantPaymentDetailDO update = new MerchantPaymentDetailDO();
            update.setDetailPaymentId(merchantPaymentDetailDO.getDetailPaymentId());
            update.setProofId(merchantPaymentDetailDO.getProofId());
            merchantPaymentService.updatePaymentDetail(update);
        }

    }

    CommonResult<String> processProof(String mchChannelCode, MerchantPaymentDetailDO merchantPaymentDetailDO) {
        try {
            MerchantProofDto merchantProofDto = channelPaymentGateway.queryDetailProof(mchChannelCode, merchantPaymentDetailDO);
            if (!StringUtils.hasText(merchantProofDto.getProofPath()) && !StringUtils.hasText(merchantProofDto.getProofId())) {
                return CommonResult.success();
            }
            MerchantPaymentDetailDO updateMerchantPaymentDetailDO = new MerchantPaymentDetailDO();
            updateMerchantPaymentDetailDO.setProofPath(merchantProofDto.getProofPath());
            updateMerchantPaymentDetailDO.setProofId(merchantProofDto.getProofId());
            updateMerchantPaymentDetailDO.setDetailPaymentId(merchantPaymentDetailDO.getDetailPaymentId());
            merchantPaymentService.updatePaymentDetail(updateMerchantPaymentDetailDO);
            merchantPaymentDetailDO.setProofPath(merchantProofDto.getProofPath());
            if (StringUtils.hasText(merchantProofDto.getProofPath())) {
                return CommonResult.success(domain + updateMerchantPaymentDetailDO.getProofPath().replace(uploadDirectory, uploadHidden));
            }
            else {
                CommonResult.error(CommonResultCode.SYSTEM_DOING);
            }
            return CommonResult.success();
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("代付凭啥生成失败:{}", e.getMessage(), e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    int updatePayOrder(MerchantPaymentDetailDO merchantPaymentDetailQuery, MerchantPaymentDetailDO merchantPaymentDetailDO) {
        if (merchantPaymentDetailDO.getStatus().equals(merchantPaymentDetailQuery.getStatus())) {
            return 0;
        }
        MerchantPaymentDetailDO updateMerchantPaymentDetailDO = new MerchantPaymentDetailDO();
        updateMerchantPaymentDetailDO.setDetailPaymentId(merchantPaymentDetailDO.getDetailPaymentId());
        updateMerchantPaymentDetailDO.setStatus(merchantPaymentDetailQuery.getStatus());
        updateMerchantPaymentDetailDO.setRemark(merchantPaymentDetailQuery.getRemark());
        updateMerchantPaymentDetailDO.setInsOrderNo(merchantPaymentDetailQuery.getInsOrderNo());
        updateMerchantPaymentDetailDO.setThirdPaymentId(merchantPaymentDetailQuery.getThirdPaymentId());
        updateMerchantPaymentDetailDO.setChannelOrderId(merchantPaymentDetailQuery.getChannelOrderId());
        updateMerchantPaymentDetailDO.setSuccessTime(merchantPaymentDetailQuery.getSuccessTime());
        int count = merchantPaymentService.updatePaymentDetail(updateMerchantPaymentDetailDO);

        if (count > 0) {
            MerchantPaymentDetailDO detailDO = merchantPaymentService.queryPaymentDetail(merchantPaymentDetailDO.getDetailPaymentId());
            log.info("代付日志  updatePayOrder 修改后详情:{}", JsonUtils.toJsonString(detailDO));
        } else {
            log.info("代付日志  updatePayOrder 修改失败:{}", JsonUtils.toJsonString(updateMerchantPaymentDetailDO));
        }
        merchantPaymentDetailDO.setStatus(merchantPaymentDetailQuery.getStatus());
        merchantPaymentDetailDO.setRemark(merchantPaymentDetailQuery.getRemark());
        merchantPaymentDetailDO.setInsOrderNo(merchantPaymentDetailQuery.getInsOrderNo());
        merchantPaymentDetailDO.setThirdPaymentId(merchantPaymentDetailQuery.getThirdPaymentId());
        merchantPaymentDetailDO.setChannelOrderId(merchantPaymentDetailQuery.getChannelOrderId());
        merchantPaymentDetailDO.setSuccessTime(merchantPaymentDetailQuery.getSuccessTime());

        merchantPaymentDetailDO.setStatus(merchantPaymentDetailQuery.getStatus());
        log.info("代付日志  updatePayOrder id {} status:{}", updateMerchantPaymentDetailDO.getDetailPaymentId(), updateMerchantPaymentDetailDO.getStatus());
        // 下发状态变更通知
        if (count > 0 && MerchantEnum.PROCESS_STATUS.SUCCESS.getCode().equals(updateMerchantPaymentDetailDO.getStatus())) {
            log.info("代付日志 updatePayOrder  orderHandler.paymentOrder id {} status:{}", updateMerchantPaymentDetailDO.getDetailPaymentId(), updateMerchantPaymentDetailDO.getStatus());
            // 统计数据
            orderHandler.paymentOrder(merchantPaymentDetailDO);
        }
        return count;
    }

}
